/*
 * ClientHandler.java
 *
 * Created on 29 februari 2008, 14:13
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package server.communication;

import java.awt.Point;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Hashtable;
import org.apache.log4j.Logger;
import org.xml.sax.InputSource;
import data.Gameroom;
import data.Gameroom.Gametype;
import data.Gebruiker;
import data.Letter;
import data.Score;
import data.SpelScore;

public class ClientHandler implements Runnable {

    private Logger logger = Logger.getLogger(ClientHandler.class);
    private Socket link = null;
    private int nummer;
    private String login;
    private PrintWriter out;
    private BufferedReader in;
    private boolean playing = false;
    private static int aantalCLientHandlers = 0;
    private ServerCommunication serverCom;

    public ClientHandler(Socket link, int ClientID, ServerCommunication server) {
        this.setLink(link);
        this.setNummer(ClientID);
        this.serverCom = server;
        setAantalCLientHandlers(getAantalCLientHandlers() + 1);
    }

    public static int getAantalClients() {
        return getAantalCLientHandlers();
    }

    public ClientHandler(Socket link) {
        this.setLink(link);
        //we houden per clienthandler ook een uniek nummer bij
        this.setNummer(getAantalCLientHandlers());
        setAantalCLientHandlers(getAantalCLientHandlers() + 1);
    }

    public void run() {
        verwerkClient();
    }

    public synchronized void AanvraagLetterWaarde(String gameroom) {
        String lijn = "<?xml version=\"1.0\"?><aanvraagLetterWaarde>";
        char s = 'A';
        for (int i = 0; i < 26; i++) {
            // String str = (String.valueOf((char)(s+i)));
            //tab.put(str, getLetterWaarde(str));
            Letter l = new Letter();

            l.setLetter((char) (s + i));
            l.setPuntenWaarde(serverCom.getBlokjesVerdeler(gameroom).getLetterWaarde(String.valueOf((char) (s + i))));
            lijn += l.convertToXML();

        }
        lijn += "<letterEnWaarde><letter>?</letter><waarde>" + serverCom.getBlokjesVerdeler(gameroom).getLetterWaarde("?") + "</waarde></letterEnWaarde></aanvraagLetterWaarde>";

        out.println(lijn);
    }

    public synchronized void isAanDeBeurt() {
        out.println("<?xml version=\"1.0\"?><isAanDeBeurt><beurt>" + true + "</beurt></isAanDeBeurt>");
    }

    public synchronized void replyCheckNicknameBestaatAl(boolean bestaat) {
        String b = bestaat ? "true" : "false";
        out.println("<?xml version=\"1.0\"?><replyCheckNicknameBestaatAl><bool>" + b + "</bool></replyCheckNicknameBestaatAl>");
    }

    public void replyGetAvatarAanvraag(int poort) {
        out.println("<?xml version=\"1.0\"?><replyGeefAvatarAanvraag><poort>" + poort + "</poort></replyGeefAvatarAanvraag>");
    }

    public synchronized void replyZendAvatarAanvraag(int poort) {
        logger.info("replyzendavataraanvraag verzenden");
        out.println("<?xml version=\"1.0\"?><replyZendAvatarAanvraag><poort>" + poort + "</poort></replyZendAvatarAanvraag>");
    }

    public synchronized void zendRandomWoord(String w) {
        out.println("<?xml version=\"1.0\"?><zendRandomWoord><woord>" + w + "</woord></zendRandomWoord>");
    }

    public synchronized void zendLetters(ArrayList<String> geefblokjes) {
        String lijn = "<?xml version=\"1.0\"?><replyLetterAanvraag><letters>";
        for (int i = 0; i < geefblokjes.size(); i++) {
            String letter = geefblokjes.get(i);
            lijn += "<letter>" + letter + "</letter>";
        }
        lijn += "</letters></replyLetterAanvraag>";
        out.println(lijn);
    }

    public synchronized void zendAantalBlokjesResterendInZakje(int aantal) {
        out.println("<?xml version=\"1.0\"?><replyBlokjesResterend><aantalInZakje>" + aantal + "</aantalInZakje></replyBlokjesResterend>");
    }

    public synchronized void StuurBord(String nickname) {
        logger.info("aanvraagBoggleBord wordt naar client gestuurd");
        out.println("<?xml version=\"1.0\"?><aanvraagBoggleBord><nickname>" + nickname + "</nickname></aanvraagBoggleBord>");
    }

    public void replyStuurBoggleBord(String[][] bogglebord) {
        String lijn ="<bord>";
        for(int i=0; i < 4; i++){
            lijn+="<rij>";
            lijn+=i;
            lijn+="</rij>";
            for(int j=0; j < 4; j++){
                lijn+="<kolom>";
                lijn+=j;
                lijn+="</kolom>";
                lijn+="<boggleLetter>";
                lijn+=bogglebord[i][j];
                lijn+="</boggleLetter>";
            }
        }
        lijn+="</bord>";
        out.println("<?xml version=\"1.0\"?><replyStuurBoggleBord>"+lijn+"</replyStuurBoggleBord>");
    }

    public void zendGoedeWoorden(ArrayList<String> goedeWoorden) {
        String lijn = "<?xml version=\"1.0\"?><goedeWoorden>";
        for (String sWoord : goedeWoorden) {
            lijn += "<goedWoord>" + sWoord + "</goedWoord>";
        }
        lijn += "</goedeWoorden>";
        logger.info(lijn);
        out.println(lijn);
    }

    private void verwerkClient() {
        try {
            //input & outputkanaal ingesteld
            in = new BufferedReader(new InputStreamReader(getLink().getInputStream()));
            out = new PrintWriter(getLink().getOutputStream(), true);

            //test-boodschap
            String sTest = in.readLine();
            logger.debug("ClientHandler " + getNummer() + ": '" + sTest + "' ontvangen");

            while (!sTest.equals("CLOSE")) {

                if (sTest.startsWith("<")) {
                    StringReader sr = new StringReader(sTest);
                    serverCom.getParser().parse(new InputSource(sr), this.getNummer());
                }

                sTest = in.readLine();
            }
        } catch (SocketException se) {
            //fout kan optreden als server plots afgesloten wordt.
            //een 'aanvaarde' fout dus...
            if (!link.isClosed()) {
                logger.error("Server plots afgesloten!");
                logger.error(se.getMessage());
            }
        } catch (IOException e) {
            logger.error(e.getMessage());
        } catch (Exception ex) {
            logger.error("Fout tijdens de 'verwerkClient' thread!");
            logger.error(ex.getMessage());
        } finally {
            closeConnectionClient();
        }
    }

    public void closeConnectionClient() {
        try {
            link.close();
            setAantalCLientHandlers(getAantalCLientHandlers() - 1);

            logger.info("Connectie met client gesloten.");
        } catch (IOException e) {
            logger.error("ClientHandler " + getNummer() + ": afsluiten mislukt!");
            logger.error(e.getMessage());
        }
    }

    //doorgeven of een speler al dan niet al is ingelogd
    public synchronized void spelerIsAlOnline(boolean online) {
        out.println("<?xml version=\"1.0\"?><replySpelerAlOnline><bool>" + online + "</bool></replySpelerAlOnline>");
    }

    //bericht naar de clients versturen
    public synchronized void zendBericht(String afzender, String bericht) {
        out.println("<?xml version=\"1.0\"?><replyChat><nickname>" + afzender + "</nickname><bericht>" + bericht + "</bericht></replyChat>");
    }

    public synchronized void zendPriveBericht(String afzender, String bericht) {
        out.println("<?xml version=\"1.0\"?><replyPriveChat><nickname>" + afzender + "</nickname><bericht>" + bericht + "</bericht></replyPriveChat>");
    }

    //er is een nieuwe speler online
    public synchronized void zendLogin(String login) {
        out.println("<?xml version=\"1.0\"?><replySpelerOnline><nickname>" + login + "</nickname></replySpelerOnline>");
    }

    //speler die offline gegaan is
    public synchronized void spelerOffline(String login) {
        out.println("<?xml version=\"1.0\"?><replySpelerOffline><nickname>" + login + "</nickname></replySpelerOffline>");
    }

    //de spelers die niet aan het spelen zijn opvragen
    public synchronized void onlineSpelers(ArrayList<Gebruiker> spelers) {
        String lijn = "<?xml version=\"1.0\"?><replyOnlineSpelers><gebruikers>";
        for (Gebruiker g : spelers) {
            lijn += g.convertToXML();
        }
        lijn += "</gebruikers></replyOnlineSpelers>";
        out.println(lijn);
    }

    public synchronized void bestaatSpeler(Gebruiker g) {
        if (g == null) {
            out.println("<?xml version=\"1.0\"?><replySpelerBestaatNiet></replySpelerBestaatNiet>");
        } else {
            out.println("<?xml version=\"1.0\"?><replySpelerBestaat>" + g.convertToXML() + "</replySpelerBestaat>");
        }
    }

    public synchronized void stuurGegevensSpeler(Gebruiker g, Score s) {

        out.println("<?xml version=\"1.0\"?><replyGetSpelerByNickname>" + g.convertToXML() + s.convertToXML()+ "</replyGetSpelerByNickname>");
    }

    public synchronized void replyMaxBeurtVerlopen(String nickname) {
        out.println("<?xml version=\"1.0\"?><replyMaxBeurtVerlopen><nickname>" + nickname + "</nickname></replyMaxBeurtVerlopen>");
    }

    public synchronized void replySpelAfgelopen() {
        out.println("<?xml version=\"1.0\"?><replySpelAfgelopen></replySpelAfgelopen>");
    }

    public synchronized void replyToonWinnaars(ArrayList<String> winnaars) {
        String lijn = "<?xml version=\"1.0\"?><replyToonWinnaars><winnaars>";
        for (String winnaar : winnaars) {
            lijn += "<winnaar>" + winnaar + "</winnaar>";
        }
        lijn += "</winnaars></replyToonWinnaars>";

        out.println(lijn);
    }

    public synchronized void replyGetGamerooms(Hashtable<String, Gameroom> gamerooms) {
        String lijn = "<?xml version=\"1.0\"?><replyGetGamerooms><gamerooms>";
        for (String name : gamerooms.keySet()) {
            lijn += gamerooms.get(name).convertToXML();
        }

        lijn += "</gamerooms></replyGetGamerooms>";
        out.println(lijn);
    }

    public synchronized void createGameroom(boolean aangemaakt, Gametype type) {
        out.println("<?xml version=\"1.0\"?><replyCreateGame><aangemaakt>" + aangemaakt + "</aangemaakt><spelType>" + type + "</spelType></replyCreateGame>");
    }

    public synchronized void gameroomToevoegen(Gameroom gr) {
        String lijn = "<?xml version=\"1.0\"?><gameroomToegevoegd>";
        lijn += gr.convertToXML();
        lijn += "</gameroomToegevoegd>";
        out.println(lijn);
    }

    public synchronized void spelGestart(String gameNaam) {
        out.println("<?xml version=\"1.0\"?><replySpelGestart></replySpelGestart>");
    }

    public synchronized void replyChatBerichtInGame(String nickname, String bericht) {
        out.println("<?xml version=\"1.0\"?><replyChatInGame><nickname>" + nickname + "</nickname><bericht>" + bericht + "</bericht></replyChatInGame>");
    }

    //Wordt opgeroepen door serverComm om een bericht te sturen in-game dat een speler
    //de gameroom joinde.
    public synchronized void replySpelerJoined(String nickname) {
        out.println("<?xml version=\"1.0\"?><replySpelerJoined><nickname>" + nickname + "</nickname></replySpelerJoined>");
    }

    public synchronized void replyLeaveGame(String nickname) {
        out.println("<?xml version=\"1.0\"?><replyLeaveGame><nickname>" + nickname + "</nickname></replyLeaveGame>");
    }

    //Bericht tonen in chatroom dat iemand een spel begonnen is
    public synchronized void replyToAllSpelerInGame(String nickname) {
        out.println("<?xml version=\"1.0\"?><replyToAllSpelerInGame><nickname>" + nickname + "</nickname></replyToAllSpelerInGame>");
    }

    //bericht tonen wie als volgende aan de beurd is
    public synchronized void replyToAllSpelerAanDeBeurt(String nickname) {
        out.println("<?xml version=\"1.0\"?><replyToAllSpelerAanDeBeurt><nickname>" + nickname + "</nickname></replyToAllSpelerAanDeBeurt>");
    }

    public synchronized void replyUpdateScoreLijst(Gameroom room) {
        String lijn = "<?xml version=\"1.0\"?><replyUpdateScores>";
        for (String nickname : room.getScores().keySet()) {
            lijn += "<userScore><nickname>" + nickname + "</nickname><score>" + room.getScores().get(nickname).intValue() + "</score></userScore>";
        }
        lijn += "</replyUpdateScores>";
        out.println(lijn);
    }

    public synchronized void zendNietGeldigeWoorden(ArrayList<String> woorden) {
        String lijn = "<?xml version=\"1.0\"?><nietGeldigeWoorden>";
        for (String sWoord : woorden) {
            lijn += "<nietGeldigeWoord>" + sWoord + "</nietGeldigeWoord>";
            logger.info("Niet geldig woord: " + sWoord + " wordt doorgestuurd naar client.");
        }
        lijn += "</nietGeldigeWoorden>";
        out.println(lijn);
    }

    public synchronized void verplaatsBlokje(Point positie, Point oudePositie, String letter, boolean blanco) {
        String lijn = "<?xml version=\"1.0\"?><replyVerplaatsBlokje><x>" + (int) positie.getX() +
                "</x><y>" + (int) positie.getY() +
                "</y><xOud>" + oudePositie.x +
                "</xOud><yOud>" + oudePositie.y +
                "</yOud><letter>" + letter +
                "</letter><blanco>" + blanco +
                "</blanco></replyVerplaatsBlokje>";
        out.println(lijn);
    }

    public synchronized void topscoreBepaald(SpelScore[] scores) {
        String lijn = "<?xml version=\"1.0\"?><replyBepaalTopscore>";
        for (int i = 0; i < 10; i++) {
            if (scores[i] != null) {
                lijn += "<topscores>" + scores[i].convertToXML() + "</topscores>";
            }
        }
        lijn += "</replyBepaalTopscore>";
        out.println(lijn);
    }

    public Socket getLink() {
        return link;
    }

    public void setLink(Socket link) {
        this.link = link;
    }

    public int getNummer() {
        return nummer;
    }

    public void setNummer(int nummer) {
        this.nummer = nummer;
    }

    public static int getAantalCLientHandlers() {
        return aantalCLientHandlers;
    }

    public static void setAantalCLientHandlers(int aAantalCLientHandlers) {
        aantalCLientHandlers = aAantalCLientHandlers;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
        serverCom.printMessage(login + " is online");
    }

    public boolean isPlaying() {
        return playing;
    }

    public void setPlaying(boolean playing) {
        this.playing = playing;
    }
}
